/*
 *  Copyright 2010 INFN - APE group
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */

#pragma once

// let's stick to boost version 1.33.1
#include <boost/thread/xtime.hpp>

#include <cuqu/config.h>
#include <cuqu/utils.h>
#include <cuqu/detail/noncopyable.h>
#include <cuqu/detail/types.h>
#include <cuqu/device_queue.h>

namespace cuqu
{
    namespace host
    {
        template <typename T>
        class queue : noncopyable
        {
        public:
            typedef T value_t;
            typedef struct detail::event<value_t> event_t;
            //typedef struct gpu_event<event_t> gpu_event_t;
            typedef struct detail::raw_queue raw_queue_t;

        private:
            unsigned int  m_nevents;
            unsigned int  m_mask;
            unsigned int  m_block_size;
            raw_queue_t   *m_h_raw_q; // host ptr
            raw_queue_t   *m_d_raw_q; // device ptr
            device::queue *m_d_gpu_q; // device ptr

#if CUQU_ENABLE_PERF_HIST
            unsigned int *m_h_hist;
            unsigned int *m_d_hist;
#endif

        public:
            queue(unsigned int num_events, unsigned int block_size);
            ~queue();

            int try_push(value_t *val);
            int timed_push(value_t *val, int timeout_ms);

            int try_fetch(value_t *val);
            int timed_fetch(value_t *val, int timeout_ms);

            device::queue *get_device_queue();

            // backward compatibility
            cuda_queue_t get_cuda_ref() { return get_device_queue(); }

            raw_queue_t *get_raw_ptr();

            // Returns the number of events in this queue.
            unsigned int size() { return m_nevents; }

#if CUQU_ENABLE_PERF_HIST 
            unsigned int *get_host_hist_ptr() { return m_h_hist; }
            unsigned int *get_device_hist_ptr() { return m_d_hist; }

            // Returns the number of elements in perf histogram.
            unsigned int hist_size() { return m_nevents + 1; }
#endif

        protected:
            void init(unsigned int num_events);
            event_t *event(int idx);
            int blocking_push(value_t *val);
            int waiting_push(value_t *val, int timeout_ms);
            int blocking_fetch(value_t *val);
            int waiting_fetch(value_t *val, int timeout_ms);
        };
    } // end namespace host
} // end namespace cuqu

#include <cuqu/detail/host_queue_inl.h>

/*
 * Local variables:
 *  mode: c++
 *  c-indent-level: 4
 *  c-basic-offset: 4
 *  tab-width: 4
 *  indent-tabs-mode: nil
 * End:
 */
